if (inweo.get("inweo.widgets.tree") != true) {
	inweo.set("inweo.widgets.tree", true);
	inweo.widgets.tree = inweo.core.widget.extend({
		cache: [],
		__cleanDragHover: function() {
			var di = $$(".treePositionImage");
			if (di != null) {
				di.removeClass("treePositionImageTop")
					.removeClass("treePositionImageOver")
					.removeClass("treePositionImageBottom")
			}
			var top = document.getElement(".treeItemDragHoverBottom");
			if (top != null) {
				top.removeClass("treeItemDragHoverBottom");
			}
			var bottom = document.getElement(".treeItemDragHoverTop");
			if (bottom != null) {
				bottom.removeClass("treeItemDragHoverTop");
			}
			var over = document.getElement(".treeItemDragHover");
			if (over != null) {
				over.removeClass("treeItemDragHover");
			}
		},
		__fixTabs: function(ul) {
			var self = this;
			var tabsNum = 0;
			if (ul.getProperty("tab") == "0") {
				tabsNum = 0;
			} else {
				tabsNum = parseInt(ul.getPrevious().getProperty("tab"));
			}
			ul.getChildren().each(function(li) {
				li.getElement("div")
					.setProperty("tab", tabsNum + 1)
					.setStyle("padding-left", tabsNum * 20);
				if (li.getElement("ul") != null) {
					self.__fixTabs(li.getElement("ul"));
				}
			});
		},
		__getDragOver: function(event) {
			var element = event.target;
			var tagName = event.target.getTag();
			var id = null;
			if (tagName == "div") {
				// li > div
				id = element.getParent().getAttribute("id");
			} else if (tagName == "img") {
				// li > div > img
				id = element.getParent().getParent().getAttribute("id");
			} else if (tagName == "a") {
				// li > div > a
				id = element.getParent().getParent().getAttribute("id");
			} else if (tagName == "span") {
				// li > div > a > span
				id = element.getParent().getParent().getParent().getAttribute("id");
			}
			var coord = event.target.getCoordinates();
			var isFolder = null;
			if (inweo.widgets.treeitems[id] instanceof inweo.widgets.treeGroup) {
				isFolder = true;
			} else {
				isFolder = false;
			}
			return {"id": id,
					"position": (event.page.y + this.widget.scrollTop) - coord.top,
					"height": coord.height,
					"isFolder": isFolder,
					"treeItem": inweo.widgets.treeitems[id]};
		},
		__getTreeIdFromElement: function(element) {
			if (element.hasClass("tree")) {
				return element.getProperty("id");
			} else {
				return this.__getTreeIdFromElement(element.getParent());
			}
		},
		__getTargetId: function(event) {
				var target = event.target;
				var tagName = target.getTag();
				var element = null;
				if ((tagName == "img") || (tagName == "span")) {
					if (tagName == "span") {
						element = "span";
						target = target.getParent();
					} else if (tagName == "img") {
						if (target.hasClass("treeImage") == true) {
							element = "treeImage";
						} else if (target.hasClass("treeGroupImage") == true) {
							element = "treeGroupImage";
						}
					}
					target = target.getParent();
				} else if (tagName == "div") {
					element = "div";
				} else {
					return null;
				}
				return {"id" : target.getParent().getAttribute("id"), "element": element}
		},
		__expandTreeGroup: function(treeItem, bool) {
			if (treeItem.__expandable == true) {
				if (bool == "toggle") {
					if (treeItem.label.widget.getProperty("aria-expanded") == "true") {
						treeItem.expand(false);
					} else {
						treeItem.expand(true);
					}
				} else {
					treeItem.expand(bool);
				}
			}
		},
		initialize: function() {
			var self = this;
			inweo.require("label");
			inweo.require("dnd", "utils");

			this.widget = new Element("ul");
			this.widget.setProperty("tab", 0);
			this.widget.addClass("tree");
			this.widget.setProperty("role", "tree");
			this.registerWidget("tree");

			var dnd = null;
			this.dropEvent = new inweo.utils.dnd.dropTarget(this);
			this.dropEvent.accept(["treeitem"]);
			this.dropEvent.onOver(function() {
				self.widget.onmousemove = function(event) {
					dnd = self.__getDragOver(new Event(event));
					if (dnd.id == null) {
						return;
					}
					var conditionTop = (dnd.isFolder == true)
										? (dnd.position < ((dnd.height * 3) / 10))
										: (dnd.position >= 0) || (dnd.position < (dnd.height / 2));
					var conditionBottom = (dnd.isFolder == true)
										? (dnd.position > ((dnd.height * 7) / 10))
										: (dnd.position > (dnd.height / 2)) && (dnd.position <= (dnd.height));
					dnd.at = "over";
					dnd.element = $(dnd.id).getElement("div");
					if (conditionTop) {
						self.__cleanDragHover();
						dnd.element.addClass("treeItemDragHoverTop");
						$$(".treePositionImage").addClass("treePositionImageTop");
						dnd.at = "top";
					}
					if (conditionBottom) {
						self.__cleanDragHover();
						dnd.element.addClass("treeItemDragHoverBottom");
						$$(".treePositionImage").addClass("treePositionImageBottom");
						dnd.at = "bottom";
					}
					if (dnd.isFolder == false) {
						return;
					}
					if ((dnd.position > ((dnd.height * 3) / 10)) && (dnd.position < ((dnd.height * 7) / 10))) {
						self.__cleanDragHover();
						dnd.element.addClass("treeItemDragHover");
						$$(".treePositionImage").addClass("treePositionImageOver");
						dnd.at = "over";
						if (dnd.element.getElement("a").getProperty("aria-expanded") == "false") {
							var dd = dnd.element;
							dd.getElement(".treeImage").addClass("treeImageLoading");
							setTimeout(function() {
								dd.getElement(".treeImage").removeClass("treeImageLoading");
								if (dd.hasClass("treeItemDragHover")) {
									if (dd.getElement("a").getProperty("aria-expanded") == "false") {
										dnd.treeItem.expand(true);
									}
								}
							}, 1000);
						}
					}
				}
			});
			this.dropEvent.onOut(function() {
				self.widget.onmousemove = function(){};
				self.__cleanDragHover();
			});
			this.dropEvent.onDrop(function() {
				self.widget.onmousemove = function(){};
				self.__cleanDragHover();
				this.text("");
				this.img.removeProperty("class");
				if (dnd.element == undefined) {
					return;
				}
				
				this.selected.each(function(selected) {
					if (dnd.at == "over") {
						selected.data.widget.injectInside(dnd.element.getNext());
					} else if (dnd.at == "top") {
						selected.data.widget.injectBefore(dnd.element.getParent());
					} else if (dnd.at == "bottom") {
						selected.data.widget.injectAfter(dnd.element.getParent());
					}
					self.__fixTabs(dnd.element.getParent().getParent());
					var id = self.__getTreeIdFromElement(dnd.element);
					inweo.widgets.trees[id].refreshCache();
					selected.data.tree = inweo.widgets.trees[id];					
				});
			});
			this.dropEvent.start();
			try {
				this.scroller = new Scroller(this.widget);
			} catch(e) {
				//alert(e.message);
			}
			/*
			try {
			this.scroller = new Scroller(this.widget, {
									area: 10,
									velocity: 0.6,
									onChange: function(x, y) {
										this.element.scrollTo(0, y);
									}
							});
			
			} catch(e) {
				alert(e.message);
			}
			//*/
			this.treeEvent = new inweo.core.event(this);
			this.treeEvent.addEvent("dblclick", function(event) {
				var target = self.__getTargetId(event);
				if (target == null) {
					return;
				}
				self.__expandTreeGroup(inweo.widgets.treeitems[target.id], "toggle");
			});
			this.treeEvent.addEvent("mousedown", function(event) {
				var target = self.__getTargetId(event);
				if (target == null) {
					return;
				}
				var treeItem = inweo.widgets.treeitems[target.id];

				//expand & collaspe
				if (target.element == "treeGroupImage") {
					self.__expandTreeGroup(treeItem, "toggle");
				}

				// select
				treeItem.select();
				//event.preventDefault();
			});
			this.treeEvent.addEvent("keydown", function(event) {
				var id = self.widget.getElement(".treeItemSelected").getParent().getProperty("id");
				var treeItem = inweo.widgets.treeitems[id];
				if (event.key == "down") {
					self.selectNext();
					event.preventDefault();
				}
				if (event.key == "up") {
					self.selectPrevious();
					event.preventDefault();
				}
				if (event.key == "left") {
					if ($type(treeItem.expand) == "function") {
						if (treeItem.expand() == "true") {
							self.__expandTreeGroup(treeItem, false);
						}
					} else {
						self.selectParent();
					}
					event.preventDefault();
				}
				if (event.key == "right") {
					if ($type(treeItem.expand) != "function") {
						return;
					}
					if (treeItem.expand() == "false") {
						self.__expandTreeGroup(treeItem, true);
					} else if (treeItem.expand() == "true") {
						self.selectNext();
					}
					event.preventDefault();
				}
			});
		},
		refreshCache: function() {
			// this.cache = this.widget.getElements(".treeItem"); no longer work at mootools 1.2, gets wrong order
			this.cache = [];
			var items = document.body.getElementsByTagName("li");
			for (var i = 0; i < items.length; i++) {
				if (items[i].hasClass("treeItem")) {
					this.cache.push(items[i]);
				}
			}
			// refresh CSS, bad bad bad firefox doesn't update itself dynamically
			this.widget.removeClass("tree").addClass("tree");
			this.updateCss();
		},
		updateCss: function(parent) {
			parent = parent || this.widget;
			parent.getElements(".treeGroupImage").each(function(img) {
				var expanded = img.getParent().getElement("a").getProperty("aria-expanded");
				if (expanded == "true") {
					img.addClass("treeGroupImageMinus");
				} else if (expanded == "false") {
					img.addClass("treeGroupImagePlus");
				}
			});
			parent.getElements(".li-last-child").each(function(li) {
				li.removeClass("li-last-child");
			});
			parent.getElements("ul li:last").each(function(li) {
				li.getElement("div").addClass("li-last-child");
			});
			this.widget.getElement("div").addClass("tree-root");
		},
		select: function(index) {
			var id = this.cache[index].getAttribute("id");
			inweo.widgets.intreeitems[id].select("parent");
		},
		selectNext: function(start) {
			var self = this;
			var stop = false;
			start = start || this.widget.getElement(".treeItemSelected").getParent().getAttribute("id");
			this.cache.each(function(treeItem, i) {
				if (stop == true) return;
				if (start == treeItem.getAttribute("id")) {
					if (i == (self.cache.length - 1)) {
						// end of tree
					} else {
						var target = self.cache[i + 1].getAttribute("id");
						if (inweo.widgets.treeitems[target].select("next") == false) {
							self.selectNext(target);
						}
					}
					stop = true;
				}
			});
		},
		selectParent: function(node) {
			node = node || this.widget.getElement(".treeItemSelected").getParent().getAttribute("id");
			var parent = $(node).getParent();
			if (parent.getProperty("role") == "group") {
				parent = parent.getParent();
			} else if (parent.getProperty("role") == "tree") {
				return false;
			}
			inweo.widgets.treeitems[parent.getAttribute("id")].select("parent");
		},
		selectPrevious: function(start){
			var self = this;
			var stop = false;
			start = start || this.widget.getElement(".treeItemSelected").getParent().getAttribute("id");
			this.cache.each(function(treeItem, i){
				if (stop == true) 
					return;
				if (start == treeItem.getAttribute("id")) {
					if ((i - 1) != -1) {
						var target = self.cache[i - 1].getAttribute("id");
						if (inweo.widgets.treeitems[target].select("previous") == false) {
							self.selectPrevious(target);
						}
					}
					stop = true;
				}
			});
		},
		unselect: function() {
			var selected = this.widget.getElement(".treeItemSelected");
			if (selected == null) {
				return;
			}
			selected.removeClass("treeItemSelected");
		}
	});
	inweo.widgets.treeItem = inweo.core.widget.extend({
		initialize: function(container) {;
			if (container instanceof inweo.widgets.tree) {
				this.container = container.widget;
				this.tree = container;
			} else if (container instanceof inweo.widgets.treeGroup) {
				this.container = container.ul;
				this.tree = container.tree;
			}

			var self = this;

			this.widget = new Element("li");
			this.widget.addClass("treeItem");

			this.tab = this.container.getPrevious();
			this.tab = (this.container.getPrevious() == null) ? 0 : this.container.getPrevious().getProperty("tab");

			this.div = new Element("div");
			this.div.setProperty("role", "presentation");
			this.div.addClass("treeItemDiv");
			this.div.setStyle("padding-left", this.tab * 20);
			this.tab++;
			this.div.setProperty("tab", this.tab);
			this.div.injectTop(this.widget);

			this.treeImage = new Element("img");
			this.treeImage.setProperty("role", "presentation");
			this.treeImage.addClass("treeGroupImage");
			this.treeImage.setProperty("src", inweo.get("path") + "skin/images/transparent.png");
			this.treeImage.injectTop(this.div);

			this.image = new Element("img");
			this.treeImage.setProperty("role", "presentation");
			this.image.addClass("treeImage");
			this.image.setProperty("src", inweo.get("path") + "skin/images/transparent.png");
			this.image.injectInside(this.div);
			
			this.label = new inweo.widgets.label();
			this.label.widget.setProperty("role", "treeitem");
			this.label.widget.injectInside(this.div);
			this.label.widget.addClass("widgetUnselectable");
			if (this.container.getProperty("role") == "tree") {
				this.label.widget.setProperty("hidden", 0);
			} else {
				/* this.container UL > getPrevious DIV > getElement("span") SPAN */
				if (this.container.getPrevious().getElement("span").getProperty("aria-expanded") == "false") {
					this.label.widget.setProperty("hidden", 1);
				} else {
					this.label.widget.setProperty("hidden", 0);
				}
			}

			this.widget.injectInside(this.container);
			this.tree.refreshCache();
			this.registerWidget("treeItem");

			this.dragEvent = new inweo.utils.dnd.dragSource(this);
			this.dragEvent.data("treeitem", this);
			this.dragEvent.onStart(function() {
				self.tree.scroller.start();
				var text = "";
				if ($type(self.expand) == "function") {
					this.img.addClass("treeImagePlus");
				} else {
					this.img.addClass("treeImage");
				}
				if (this.selected.length >= 2) {
					text += "(" + this.selected.length + ") ";
					this.img.removeProperty("class");
					this.img.addClass("treeImageMultiDrag");					
				}
				text += self.text();
				this.text(text);
			});
			this.dragEvent.onComplete(function() {
				self.tree.scroller.stop();
				this.img.removeProperty("class");
			});
			this.dragEvent.start();
		},
		select: function(move) {
			if (this.widget.getElement("a").getAttribute("hidden") == 1) {
				return false;
			}
			var selected = document.getElement(".treeItemSelected");
			if (selected != null) {
				selected.removeClass("treeItemSelected");
			}
			this.div.removeClass("treeItemHighlight");
			this.div.addClass("treeItemSelected");

			var coord = this.div.getCoordinates();
			var top = coord.top - this.tree.widget.getCoordinates().top;
			var treeHeight = parseInt(this.tree.widget.getStyle("height"));
			var scroll = this.tree.widget.scrollTop;
			var height = coord.height;
			if (move == null) {
				return;
			} else if (move == "next") {
				if ((top + height) > (treeHeight + scroll)) {
					this.display(false);
				}
			} else if (move == "previous") {
				if ((top + 3) < scroll) {
					this.display(true);
				}
			} else if (move == "parent") {
				this.display(true);
			}
		},
		text: function(string) {
			if (string != null) {
				return this.label.text(string);
			} else {
				return this.label.text();
			}
		}
	});
	inweo.widgets.treeGroup = inweo.widgets.treeItem.extend({
		__setHiddenValue: function(ul, value) {
			var self = this;
			ul.getElements("li").each(function(li) {
				li.getElement("a").setProperty("hidden", 0);
				var ul = li.getElement("ul");
				if ($type(ul) == "element") {
					if (li.getElement("a").getProperty("aria-expanded") == "true") {
						self.__setHiddenValue(ul, value);
					}
				}
			});
		},
		expand: function(bool) {
			if (bool == false) {
				this.label.widget.setProperty("tabindex", -1);
				this.label.widget.setProperty("aria-expanded", "false");
				this.treeImage.removeClass("treeGroupImageMinus");
				this.treeImage.addClass("treeGroupImagePlus");
				this.image.removeClass("treeImageMinus");
				this.image.addClass("treeImagePlus");
				this.ul.setStyle("display", "none");
				this.ul.getElements("li").each(function(li) {
					li.getElement("a").setProperty("hidden", 1);
				});
			} else if (bool == true) {
				this.label.widget.setProperty("tabindex", 0);
				this.label.widget.setProperty("aria-expanded", "true");
				this.treeImage.removeClass("treeGroupImagePlus");
				this.treeImage.addClass("treeGroupImageMinus");
				this.image.removeClass("treeImagePlus");
				this.image.addClass("treeImageMinus");
				this.ul.setStyle("display", "block");
				this.__setHiddenValue(this.ul, 0);
			} else {
				return this.label.widget.getProperty("aria-expanded");
			}
		},
		expandable: function(bool) {
			this.__expandable = bool;
		},
		initialize: function(container) {
			this.parent(container);

			this.widget.addClass("treeGroup");
			this.label.widget.setProperty("role", "treeitem");
			this.label.widget.setProperty("aria-expanded", "true");
			this.image.addClass("treeImageMinus");

			this.ul = new Element("ul");
			this.ul.setProperty("role", "group");
			this.ul.injectInside(this.widget);
			
			this.expandable(true);
		}
	});
	inweo.widgets.tree.tag = inweo.core.tag.extend({
		insert: function(element, obj) {
			obj.widget.setHTML(element.innerHTML);
			this.parent(element, obj);
		}
	});
	inweo.widgets.treeItem.tag = inweo.core.tag.extend({
		getWidgetObject: function() {
			if (this.element.getParent().getProperty("role") == "tree") {
				var id = this.element.getParent().getProperty("id");
				return new inweo.widgets.treeItem(inweo.widgets.trees[id]);
			} else if (this.element.getParent().getProperty("role") == "group") {
				var id = this.element.getParent().getParent().getProperty("id");
				return new inweo.widgets.treeItem(inweo.widgets.treeitems[id]);
			}
		}
	});
	inweo.widgets.treeGroup.tag = inweo.core.tag.extend({
		getWidgetObject: function() {
			if (this.element.getParent().getProperty("role") == "tree") {
				var id = this.element.getParent().getProperty("id");
				var container = inweo.widgets.trees[id];
			} else if (this.element.getParent().getProperty("role") == "group") {
				var id = this.element.getParent().getParent().getProperty("id");
				var container = inweo.widgets.treeitems[id];
			}
			var tg = new inweo.widgets.treeGroup(container);
			tg.ul.setHTML(this.element.innerHTML);
			return tg;
		}
	});
}